package com.jule.goldfast.game.network.protocol.reqs;

import JoloProtobuf.GameSvr.JoloGame;
import com.google.common.base.Strings;
import com.jule.core.common.log.LoggerUtils;
import com.jule.core.jedis.JedisPoolWrap;
import com.jule.core.jedis.StoredObjManager;

import com.jule.goldfast.base.model.GameRoomTableSeatRelationModel;
import com.jule.goldfast.game.dao.DBUtil;
import com.jule.goldfast.game.dao.bean.RoomConfigModel;
import com.jule.goldfast.game.model.PlayerInfo;
import com.jule.goldfast.base.enums.PlayerStateEnum;
import com.jule.goldfast.base.enums.TableStateEnum;
import com.jule.goldfast.game.play.AbstractTable;
import com.jule.goldfast.game.play.TableUtil;
import com.jule.goldfast.game.service.LogService;
import com.jule.goldfast.game.service.PlayerService;
import com.jule.goldfast.game.service.RoomStateService;
import com.jule.goldfast.game.service.TableService;
import com.jule.goldfast.game.utils.log.TableLogUtil;
import com.jule.goldfast.game.vavle.notice.NoticeBroadcastMessages;
import com.jule.goldfast.base.dao.bean.User;
import com.jule.goldfast.base.enums.ErrorCodeEnum;
import com.jule.goldfast.base.enums.GameConst;
import com.jule.goldfast.base.enums.RedisConst;
import com.jule.goldfast.base.enums.RoleType;
import com.jule.goldfast.base.model.RoomTableRelationModel;
import com.jule.goldfast.game.config.Config;
import com.jule.goldfast.game.network.protocol.ClientReq;
import com.jule.goldfast.game.network.protocol.acks.JoloGame_ApplySitDownAck_50001;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.List;

/**
 * 申请入座(无指定座位随机)
 * return：
 */
@Slf4j
public class JoloGame_ApplySitDownReq_50001 extends ClientReq {
    private long time;

    public JoloGame_ApplySitDownReq_50001(int functionId) {
        super(functionId);
    }

    private JoloGame.JoloGame_ApplySitDownReq req;

    @Override
    public void readPayLoadImpl(ByteBuf buf) throws Exception {
        time = System.currentTimeMillis();
        byte[] blob = new byte[buf.readableBytes()];
        buf.readBytes(blob);
        req = JoloGame.JoloGame_ApplySitDownReq.parseFrom(blob);
    }

    @Override
    public void processImpl() throws Exception {
        log.debug("收到消息, functionId->" + functionId + ", reqNum->" + header.reqNum + ", req->" + req.toString());
        JoloGame.JoloGame_ApplySitDownAck.Builder ack = JoloGame.JoloGame_ApplySitDownAck.newBuilder();
        AbstractTable table = null;

        String userId = req.getUserId();
        String roomId = req.getRoomId();
        String tableId = req.getTableId();
        int seatNum = req.getSeatNum();
        double buyInScore = -1;
        boolean success = StoredObjManager.hsetnx(
                RedisConst.HASH_SET_NX.getProfix() + "REQ",
                RedisConst.HASH_SET_NX.getField() + functionId + userId,
                "" + System.currentTimeMillis());
        if (!success) {
            log.error("找不到该桌子得缓存：{}",success);
            ack.setSeatNum(0);
            ack.setResult(-1).setResultMsg("找不到该桌子得缓存");
            ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
            return;
        }
        ack.setUserId(userId);
        ack.setRoomId(roomId);
        ack.setTableId(tableId);
        ack.setSeatNum(seatNum);
        try {
            //缓存玩家使用的服务器IP、负载时使用
            JedisPoolWrap.getInstance().set(RedisConst.USER_LOGIN_GAME_URL.getProfix(), Config.REST_IP + ":" + Config.REST_PORT, -1);
            //从redis获取玩家的信息
            RoomTableRelationModel roomTable = RoomStateService.getInstance().getExistTable("" + header.gameId, roomId, tableId);

            if (roomTable == null) {
                log.error("can't found table, gameId:{},roomId:{},tableId:{}", header.gameId, roomId, tableId);
                ack.setSeatNum(0);
                ack.setResult(-2).setResultMsg("找不到该房间");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            table = TableService.getInstance().addNewTable(header.gameId + "", roomId, tableId);

            /*
             * add by gx 20181009
             * 修改桌子状态为每玩完一局，自动散桌。并且在玩牌过程中，不允许玩家加入桌子。
             */
            if (table.getTableStateEnum().getValue() > TableStateEnum.GAME_READY.getValue()) {
                log.error("桌子状态不符：" + table.toString());
                ack.setSeatNum(0);
                ack.setResult(-3).setResultMsg("桌子状态不符");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                StoredObjManager.hdel(RedisConst.USER_TABLE_SEAT.getProfix(), RedisConst.USER_TABLE_SEAT.getField() + userId);
                return;
            }

            //用户信息：从缓存获取
            User user = StoredObjManager.hget(RedisConst.USER_INFO.getProfix(), RedisConst.USER_INFO.getField() + userId, User.class);
            if (null == user) {
                log.debug("can't found user, userId->" + userId);
                ack.setSeatNum(0);
                ack.setResult(-4).setResultMsg("找不到该玩家");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            String icon = StringUtils.isEmpty(user.getUser_defined_head()) ? user.getIco_url() : user.getUser_defined_head();
            PlayerInfo player = table.getPlayer(userId);

            if (player == null) {
                player = new PlayerInfo(roomTable, userId, user.getNick_name(), icon, RoleType.getRoleType(user.getChannel_id()));
            }
            String res = StoredObjManager.hget(RedisConst.TABLE_USERS.getProfix() + header.gameId + player.getRoomId() + player.getTableId(),
                    RedisConst.TABLE_USERS.getField() + player.getPlayerId());
            log.info("res=========" + res);
            log.debug("========="+RedisConst.TABLE_USERS.getProfix() + header.gameId + player.getRoomId() + player.getTableId());
            log.debug("========="+RedisConst.TABLE_USERS.getField() + player.getPlayerId());
            if (Strings.isNullOrEmpty(res)) {
                log.debug(" 桌内查无此人, userId->" + userId + ", roomId->" + roomId + ",tableId->" + tableId);
                ack.setSeatNum(0);
                ack.setResult(-5).setResultMsg("桌内查无此人");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }
            if (res.equals("" + PlayerStateEnum.siteDown.getValue())) {
                log.error("Failed to sit down many times");
                ack.setSeatNum(0);
                ack.setResult(-6).setResultMsg("多次坐下失败");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }
            //修改相关map内容，增加新玩家入桌状态
            table.joinTable(player);

            if (user.getMoney() <= 0) {
                log.error("玩家金额不足");
                ack.setSeatNum(0);
                ack.setResult(-7).setResultMsg("玩家金额不足");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            if (req.hasBuyInScore()) {
                buyInScore = req.getBuyInScore();
            } else {
                buyInScore = user.getMoney();
            }

            double currScoreStore = user.getMoney(); //玩家当前积分库存
            if (currScoreStore < buyInScore) {
                log.error("玩家当前金额低于下注金额");
                ack.setSeatNum(0);
                ack.setResult(-8).setResultMsg("玩家当前金额低于下注金额");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            if (!req.hasRoomId()) {
                log.debug("找不到请求得房间id");
                ack.setSeatNum(0);
                ack.setResult(-9).setResultMsg("找不到请求得房间id");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            //创建player对象
            log.debug(table.getPlayer(userId) + ":---" + userId);
            player = table.getPlayer(userId);
            if (null == player) {
                log.debug("can't found suitable player. player->" + player);
                ack.setSeatNum(0);
                ack.setResult(-10).setResultMsg("找不到该玩家");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }


            ack.setResult(1);
            ack.setTableState(table.getTableStateEnum().getValue());
            ack.setCurrPlayScore(buyInScore);
            log.debug("roomId->" + roomId + ", tableId->" + tableId);
            ack.setTotalAlreadyBet(0);

            if (table.getInGamePlayersBySeatNum().containsKey(seatNum)
                    && !table.getInGamePlayersBySeatNum().get(seatNum).getPlayerId().equals(player.getPlayerId())) {// modify lyb20180722 字符串用equals对比
                log.error("-11  该玩家不在桌内 the seat is already occupied。seatNum:{},playInfo->{},current seat's playerInfo:{}", seatNum, player.playerToString(),
                        table.getInGamePlayersBySeatNum().get(seatNum).playerToString());
                ack.setSeatNum(0);
                ack.setResult(-11).setResultMsg("该玩家不在桌内");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            List<RoomConfigModel> configList = DBUtil.getRoomConfigFromDb();
            Collections.sort(configList);
            log.debug(player.playerToString() + "当前房间最低下注额：" + table.getRoomConfig().getAnte());
            if (buyInScore < table.getRoomConfig().getAnte() || buyInScore < configList.get(0).getAnte()) {
                log.debug(player.playerToString() + "玩家积分低于当前房间最低下注额 ante->" + table.getRoomConfig().getAnte());
                ack.setSeatNum(0);
                ack.setResult(-12).setResultMsg("玩家桌内金额不足");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            //如果未指定座位下，那么随机分配一个座位给玩家
            if (req.getSeatNum() < 1 || req.getSeatNum() > 5) {
                seatNum = table.getNulSeatNum();
                log.info("Random seatNum" + seatNum + req.toString());
            }

            if (seatNum == 0) {
                log.debug("玩家座位号异常：{}",seatNum);
                ack.setSeatNum(0);
                ack.setResult(-13).setResultMsg("玩家座位号异常");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
                return;
            }

            //初始化ack信息
            ack.setSeatNum(seatNum);
            boolean suc = table.sitDown(seatNum, userId);
            //坐下
            if (suc) {
                //增加一个已坐下判断
                StoredObjManager.hset(RedisConst.TABLE_USERS.getProfix() + header.gameId + player.getRoomId() + player.getTableId(),
                        RedisConst.TABLE_USERS.getField() + player.getPlayerId(), "" + PlayerStateEnum.siteDown.getValue());

                StoredObjManager.hset(RedisConst.CHANGE_TABLE_STAT.getProfix(),
                        RedisConst.CHANGE_TABLE_STAT.getField() + userId, "0");
                //代入积分
                //long currentMoney = MoneyService.getInstance().buyScore(player.getPlayerId(), buyInScore);
                log.debug(player.playerToString() + "玩家带入筹码：" + buyInScore);
                player.setTotalWinLoseScore(0);
                player.setState(PlayerStateEnum.siteDown); //修改玩家状态值
                player.setPlayScoreStore(buyInScore);
                player.setTotalTakeInScore(buyInScore);
                //本局癞子牌
                ack.setMixedCardId(0);
                //本局换出去的牌
                ack.addAllChangeCards(table.getChangeCards());
                ack.setGameOrderId(table.getCurrGameOrderId());
                //判断玩家在不在游戏中
                if (table.getTableStateEnum().getValue() > TableStateEnum.GAME_READY.getValue()) {
                    ack.setNotInGame(1);
                }
                ack.setTableState(table.getTableStateEnum().getValue());
                ack.setPlayType("");
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack
                        .addAllPlayerInfoList(TableUtil.getPlayers(table)).build(), header));
                //桌子复盘记录（坐下）

                log.debug("玩家入座成功：" + player.toSitDownString());

                //广播玩家入座
                try {
                    NoticeBroadcastMessages.playerSitDown(table, userId);
                } catch (Exception ex) {
                    log.error("SendNotice ERROR：", ex);
                }
                //保存所在桌内位置信息
                //判断：如果在座玩家超过两人并且桌子状态为空闲状态
                TableService.getInstance().playGame(table); //开始游戏
                if (!user.getChannel_id().equals(RoleType.ROBOT.getTypeName())) {
                    PlayerService.getInstance().onPlayerLogin(userId);
                }

                //发送坐下日志
                LogService.OBJ.sendGamesitLog(user, table);
            } else {
                table.addNullSeat(seatNum);//如果
                ack.setSeatNum(0);
                log.debug("  -9  玩家入座失败" + player.playerToString());
                ack.setResult(-9).setResultMsg(ErrorCodeEnum.GAME_50001_7.getCode());
                ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
            }
            TableLogUtil.sitdown(functionId, "SitDownReq", userId, user.getNick_name(), user.getChannel_id(), "" + table.getPlayType(),
                    table.getRoomId(), table.getTableId(), seatNum, suc, player.getPlayScoreStore(), table.getInGamePlayersBySeatNum().size());
            long timeMillis = System.currentTimeMillis() - time;
            if (timeMillis > GameConst.COST_TIME) {
                LoggerUtils.performance.info("ApplySitDownReq_50001,cost time:{},req:{}", timeMillis, req.toString());
            }
        } catch (Exception e) {
            ack.setSeatNum(0).setResult(-10).setResultMsg(ErrorCodeEnum.GAME_50002_2.getCode());//座位号是必须的字段
            ctx.writeAndFlush(new JoloGame_ApplySitDownAck_50001(ack.build(), header));
            log.error("", e);
        } finally {
            log.debug("SiteDown ACK info: " + ack.toString());
            if (null != table) {
                log.debug("All Player info: " + System.getProperty("line.separator") + TableUtil.toStringAllPlayers(table));
                log.debug("InGame Player info: " + System.getProperty("line.separator") + TableUtil.toStringInGamePlayers(table));
            }
            StoredObjManager.hdel(RedisConst.HASH_SET_NX.getProfix() + "REQ",
                    RedisConst.HASH_SET_NX.getField() + functionId + userId);
        }
    }
}
